use crate::{cmd::{Command, CommandExecutor}, RespError};

use bytes::BytesMut;
use futures::SinkExt;
use tokio::net::TcpStream;
use anyhow::Result;
use tokio_stream::StreamExt;

use crate::{Backend, RespDecode, RespEncode, RespFrame};
use tokio_util::codec::{Decoder, Encoder, Framed};



#[derive(Debug)]
struct RedisRequest {
    frame: RespFrame,
    backend: Backend,

}
#[derive(Debug)]
struct RedisResponse {
    frame: RespFrame,
}

#[derive(Debug)]
struct RespFrameCodes;  

pub async fn stream_handler(stream: TcpStream,backend: Backend) -> Result<()> {
    let mut framed: Framed<TcpStream, RespFrameCodes> = Framed::new(stream, RespFrameCodes);
    // Read the first line from the `LineCodec` stream to get the username.
    loop {
    match framed.next().await{
        Some(Ok(frame)) => {
            let request: RedisRequest = RedisRequest{
                frame,
                backend: backend.clone(),
            };
            let response = request_handler(request).await?;
            framed.send(response.frame).await?;
        }
        Some(Err(e)) => return Err(e.into()),
        None => return Ok(()),
        }
    }
}

async fn request_handler(request: RedisRequest) -> Result<RedisResponse> {
    let (frame, backend) = (request.frame, request.backend);
    let cmd: Command = Command::try_from(frame)?;
    let frame = cmd.execute(&backend);
    Ok(RedisResponse { frame })
}



impl Encoder<RespFrame> for RespFrameCodes {
    type Error = anyhow::Error;
    fn encode(&mut self, item: RespFrame, dst: &mut BytesMut) -> Result<(), Self::Error> {
        let data = item.encode();
        dst.extend_from_slice(&data);

        Ok(())
    }
}

impl Decoder for RespFrameCodes {
    type Item = RespFrame;
    type Error = anyhow::Error;

    fn decode(&mut self, src: &mut BytesMut) -> Result<Option<RespFrame>> {
        match RespFrame::decode(src) {
            Ok(frame) => Ok(Some(frame)),
            Err(RespError::NotComplete) => Ok(None),
            Err(e) => Err(e.into()),
        }

    }
    
}